package com.inkyi.assistant.app.component.rsyntax;


import com.inkyi.assistant.app.base.BaseFrame;
import com.inkyi.assistant.app.base.InkEditor;
import com.inkyi.assistant.app.component.rsyntax.event.DefaultHyperlinkListener;
import com.inkyi.assistant.app.component.rsyntax.event.RSyntaxTextEvent;
import com.inkyi.assistant.app.component.rsyntax.event.RSyntaxTextListener;
import com.inkyi.framework.common.utils.EmptyHelper;
import com.inkyi.framework.common.utils.JsonUtils;
import com.inkyi.framework.daqian.share.layout.VerticalLayout;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rtextarea.RTextScrollPane;
import org.fife.ui.rtextarea.SearchContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

public class RSyntaxTextEditor extends JPanel implements InkEditor<String> {

    public static final Logger log = LoggerFactory.getLogger(RSyntaxTextEditor.class);

    public static final String EDITOR_TYPE = "RSyntaxTextEditor";

    private final Map<Object, Object> propertyMap = new ConcurrentHashMap<>();

    private final RSyntaxTextArea textArea = new RSyntaxTextArea();

    private final RTextScrollPane scrollPane = new RTextScrollPane(textArea);
    /**
     * 头部区域
     */
    private final JPanel headerArea = new JPanel();
    /**
     * 脚部区域
     */
    private final JPanel footerArea = new JPanel();
    /**
     * 搜索上下文
     */
    private final SearchContext searchContext = new SearchContext();
    /**
     * 工具栏
     */
    private RSyntaxTextToolBar toolbar;
    /**
     * 查找替换工具条
     */
    private RSyntaxTextFindBar findReplaceBar;

    public String getId() {
        return (String) getProperty("rste.uuid");
    }

    public void setId(String ids) {
        putProperty("rste.uuid", ids);
    }

    public RSyntaxTextEditor() {
        setupUI();
        initConfig();
    }

    public synchronized String getContent() {
        return textArea.getText();
    }

    @Override
    public String getEditorType() {
        return EDITOR_TYPE;
    }

    @Override
    public JComponent getComponent() {
        return textArea;
    }

    @Override
    public void putProperty(Serializable key, Object value) {
        propertyMap.put(key, value);
    }

    @Override
    public Object getProperty(Serializable key) {
        return propertyMap.get(key);
    }

    @Override
    public void removeProperty(Serializable key) {
        propertyMap.remove(key);
    }

    public synchronized void setContent(String content) {
        textArea.setText(content);
    }

    public void addListener(RSyntaxTextListener listener) {
        listenerList.add(RSyntaxTextListener.class, listener);
    }

    public void delListener(RSyntaxTextListener listener) {
        listenerList.remove(RSyntaxTextListener.class, listener);
    }


    public void setupUI() {

        this.setLayout(new BorderLayout());
        headerArea.setLayout(new VerticalLayout());
        footerArea.setLayout(new VerticalLayout());

        // 头部工具栏区域
        toolbar = new RSyntaxTextToolBar(textArea, scrollPane);
        toolbar.setLayout(new FlowLayout(FlowLayout.LEADING));
        headerArea.add(toolbar);
        headerArea.setBackground(Color.YELLOW);
        headerArea.setSize(new Dimension(0, 200));

        // 替换栏
        findReplaceBar = new RSyntaxTextFindBar(false, textArea, searchContext);
        findReplaceBar.setVisible(false);
        footerArea.add(findReplaceBar);

        this.add(scrollPane, BorderLayout.CENTER);
        this.add(headerArea, BorderLayout.NORTH);
        this.add(footerArea, BorderLayout.SOUTH);
    }

    public void initConfig() {
        toolbar.getViewLineNumberCheckBox().setSelected(true);
        toolbar.getViewLineHighlightCheckBox().setSelected(true);
        toolbar.getWordWrapCheckBox().setSelected(true);


        if (EmptyHelper.isEmpty(textArea.getSyntaxEditingStyle())) {
            textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_MARKDOWN);
        }
        textArea.setMaximumSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
        textArea.setCodeFoldingEnabled(true); // 代码折叠
        textArea.setAntiAliasingEnabled(true);// 抗混叠
        textArea.setPaintMatchedBracketPair(true);
        textArea.setAnimateBracketMatching(true); // 花括号匹配
        textArea.setDoubleBuffered(true); // 双缓冲
        // 超链接
        textArea.setHyperlinksEnabled(true);
        textArea.addHyperlinkListener(new DefaultHyperlinkListener());

        JComponent editorThis = this;
        // 文本域键盘事件
        textArea.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent evt) {
                SwingUtilities.invokeLater(() -> {
                    if ((evt.isControlDown() || evt.isMetaDown()) && evt.getKeyCode() == KeyEvent.VK_S) {
                        log.info("save");
                        RSyntaxTextEvent event = new RSyntaxTextEvent(editorThis, RSyntaxTextEvent.TYPE_DO_SAVE);
                        event.setConfig(getEditConfig());
                        event.setContent(getContent());
                        doActionPerformed(event);
                    } else if (((evt.isControlDown() || evt.isMetaDown()) && evt.isShiftDown() && evt.getKeyCode() == KeyEvent.VK_F)
                            || evt.isMetaDown() && evt.isAltDown() && evt.getKeyCode() == KeyEvent.VK_L) {
                        log.info("format");
                        format();
                    } else if ((evt.isControlDown() || evt.isMetaDown()) && evt.getKeyCode() == KeyEvent.VK_F) {
                        log.info("showFindPanel");
                        findReplaceBar.setShowReplace(false);
                        findReplaceBar.setVisible(true);
                        findReplaceBar.updateUI();
                    } else if ((evt.isControlDown() || evt.isMetaDown()) && evt.getKeyCode() == KeyEvent.VK_R) {
                        log.info("showFindPanel");
                        findReplaceBar.setShowReplace(true);
                        findReplaceBar.setVisible(true);
                        findReplaceBar.updateUI();
                    } else if ((evt.isControlDown() || evt.isMetaDown()) && evt.getKeyCode() == KeyEvent.VK_N) {
                        log.info("new");
                        RSyntaxTextEvent event = new RSyntaxTextEvent(editorThis, RSyntaxTextEvent.TYPE_DO_CREATE);
                        doActionPerformed(event);
                    }
                });
            }
        });
        // 文本变更监听
        textArea.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                RSyntaxTextEvent event = new RSyntaxTextEvent(editorThis, RSyntaxTextEvent.TYPE_DO_FAST_SAVE);
                event.setContent(getContent());
                SwingUtilities.invokeLater(() -> {
                    doActionPerformed(event);
                });
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                RSyntaxTextEvent event = new RSyntaxTextEvent(editorThis, RSyntaxTextEvent.TYPE_DO_FAST_SAVE);
                event.setContent(getContent());
                SwingUtilities.invokeLater(() -> {
                    doActionPerformed(event);
                });
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                RSyntaxTextEvent event = new RSyntaxTextEvent(editorThis, RSyntaxTextEvent.TYPE_DO_FAST_SAVE);
                event.setContent(getContent());
                SwingUtilities.invokeLater(() -> {
                    doActionPerformed(event);
                });
            }
        });

        // 头部工具栏大小自动调整  TODO 可以写Blog
        this.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                Component[] components = toolbar.getComponents();
                int compMaxY = 0; // 按钮最大的Y位置
                int compHeight = 0; // 按钮的高度
                for (Component component : components) {
                    compMaxY = Math.max(compMaxY, component.getY());
                    compHeight = component.getHeight();
                }
                // 新的高速，Y位置 + 组件的高度
                int newHeight = compMaxY + compHeight;
                // 获取工具栏大小
                Dimension toolbarSize = toolbar.getSize();
                int newToolHeight = newHeight + 2; // 新高度 + 间隙
                toolbarSize.height = newToolHeight;
                toolbar.setPreferredSize(toolbarSize);
            }
        });
    }

    /**
     * 文本格式化
     */
    public void format() {
        try {
            String text = textArea.getText();
            String format;
            String selectedSyntax = (String) toolbar.getStyleComboBox().getSelectedItem();
            if (EmptyHelper.isEmpty(text) || EmptyHelper.isEmpty(selectedSyntax) || Objects.equals("NONE", selectedSyntax)) {
                return;
            }
            switch (selectedSyntax) {
                case SyntaxConstants.SYNTAX_STYLE_SQL:
                    format = text;
                    break;
                case SyntaxConstants.SYNTAX_STYLE_JSON:
                    format = text;
                    break;
                case SyntaxConstants.SYNTAX_STYLE_JSON_WITH_COMMENTS:
                    format = text;
                    break;
                case SyntaxConstants.SYNTAX_STYLE_JAVA:
                    format = text;
                    break;
                default:
                    JOptionPane.showMessageDialog(this, "尚不支持对该语言格式化！\n", "不支持该语言",
                            JOptionPane.INFORMATION_MESSAGE);
                    return;
            }
            textArea.setText(format);
        } catch (Exception e) {
            JOptionPane.showMessageDialog(this, "格式化失败！\n\n" + e.getMessage(), "失败",
                    JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * 查找组合框所选项目
     *
     * @param comboBox 组合框
     * @return {@link Object }
     */
    private Object findComboBoxSelectedItem(JComboBox<?> comboBox) {
        if (comboBox == null || comboBox.getSelectedItem() == null) {
            return null;
        }
        return comboBox.getSelectedItem();
    }

    /**
     * 收集配置
     */
    public RSyntaxTextConfig getEditConfig() {
        RSyntaxTextConfig config = new RSyntaxTextConfig();
        {
            Object selectedItem = findComboBoxSelectedItem(toolbar.getStyleComboBox());
            if (selectedItem != null) {
                config.setStyle(selectedItem.toString());
            }
        }
        {
            Object selectedItem = findComboBoxSelectedItem(toolbar.getFontNameComboBox());
            if (selectedItem != null) {
                config.setFontName(selectedItem.toString());
            }
        }
        {
            Object selectedItem = findComboBoxSelectedItem(toolbar.getFontSizeComboBox());
            if (selectedItem != null) {
                config.setFontSize(selectedItem.toString());
            }
        }
        {
            Object selectedItem = findComboBoxSelectedItem(toolbar.getThemeComboBox());
            if (selectedItem != null) {
                config.setTheme(selectedItem.toString());
            }
        }
        config.setViewLineNumber(toolbar.getViewLineNumberCheckBox().isSelected());
        config.setViewLineHighlight(toolbar.getViewLineHighlightCheckBox().isSelected());
        config.setWordWrap(toolbar.getWordWrapCheckBox().isSelected());
        config.setCodeFolding(toolbar.getCodeFoldingCheckBox().isSelected());
        return config;
    }

    /**
     * 刷新编辑器
     */
    public void setEditConfig(RSyntaxTextConfig config) {
        if (EmptyHelper.isNotEmpty(config.getStyle())) {
            toolbar.getStyleComboBox().setSelectedItem(config.getStyle());
        }
        if (EmptyHelper.isNotEmpty(config.getFontName())) {
            toolbar.getFontNameComboBox().setSelectedItem(config.getFontName());
        }
        if (EmptyHelper.isNotEmpty(config.getFontSize())) {
            toolbar.getFontSizeComboBox().setSelectedItem(config.getFontSize());
        }
        if (EmptyHelper.isNotEmpty(config.getTheme())) {
            toolbar.getThemeComboBox().setSelectedItem(config.getTheme());
        }
        if (EmptyHelper.isNotNull(config.getViewLineNumber())) {
            toolbar.getViewLineNumberCheckBox().setSelected(config.getViewLineNumber());
        }
        if (EmptyHelper.isNotNull(config.getViewLineHighlight())) {
            toolbar.getViewLineHighlightCheckBox().setSelected(config.getViewLineHighlight());
        }
        if (EmptyHelper.isNotNull(config.getWordWrap())) {
            toolbar.getWordWrapCheckBox().setSelected(config.getWordWrap());
        }
        if (EmptyHelper.isNotNull(config.getCodeFolding())) {
            toolbar.getCodeFoldingCheckBox().setSelected(config.getCodeFolding());
        }

    }

    /**
     * 执行动作
     *
     * @param event 事件
     */
    private void doActionPerformed(RSyntaxTextEvent event) {
        RSyntaxTextListener[] listeners = listenerList.getListeners(RSyntaxTextListener.class);
        for (RSyntaxTextListener listener : listeners) {
            listener.actionPerformed(event);
        }
    }

    public static void main(String[] args) {
        BaseFrame frame = new BaseFrame("ComboBox Example", 800, 600);

        RSyntaxTextEditor textPanel = new RSyntaxTextEditor();

        JButton getContent = new JButton("Get Content");
        getContent.addActionListener(e -> {
            System.out.println(textPanel.getContent());
        });
        JButton getConfig = new JButton("Get config");
        getConfig.addActionListener(e -> {
            System.out.println(JsonUtils.toJSONString(textPanel.getEditConfig()));
        });

        JButton setContent = new JButton("set content");
        setContent.addActionListener(e -> {
            textPanel.setContent("fdsafdsafdsakjfkldjsa;lkfjdsa;jfd;slkajfld;sajf");
        });

        JButton setConfig = new JButton("set config");
        setConfig.addActionListener(e -> {
            RSyntaxTextConfig config = new RSyntaxTextConfig();
            config.setFontSize("15");
            textPanel.setEditConfig(config);
        });


        JPanel buttionPanel = new JPanel();
        buttionPanel.add(getContent);
        buttionPanel.add(getConfig);
        buttionPanel.add(setContent);
        buttionPanel.add(setConfig);


        frame.getContentPane().add(textPanel, BorderLayout.CENTER);
        frame.getContentPane().add(buttionPanel, BorderLayout.SOUTH);

        frame.setVisible(true);
    }


}
